<script setup lang="ts">
import {computed, h} from 'vue';
import {
	FileAddOutlined,
	PictureOutlined,
	PaperClipOutlined,
	GlobalOutlined,
	DownOutlined,
} from '@ant-design/icons-vue';
import {App, type MenuProps} from 'ant-design-vue';
import {Sender, Attachments, type AttachmentsProps,}from 'ant-design-x-vue';
import useRecord from "@/hooks/useRecord.ts";

const { message } = App.useApp();
//const {isMobile} = useKV()

/* props */
const props =defineProps({
	uploadImageEnable: { type:Boolean, default:true, required:false, },
	uploadDocumentEnable: { type:Boolean, default:true, required:false, },
	uploadSpeechEnable: { type:Boolean, default:true, required:false, },
	source: { type:String, default:'chat',required:false,},
})

/* emits */
const emit = defineEmits(['onSend','onCancel']);

/* data */
const inPush = inject('inPush',ref(false)); //是否正处于信息推流中？
const linkNet =ref(false); //是否连网
const headerOpen = ref(false); //头部区是否打开
const uploadUrl = import.meta.env.VITE_API_URL + import.meta.env.VITE_URI_UPLOAD //上传文件路径
const uploadType=ref(-1) //-1还没开始选 0图片、1文档、2语音音频
const uploadTypeChangeConfirm=ref(false)
const maxUploadCount = ref(3) //允许上传的最大文件数
const fileItems=ref<AttachmentsProps['items']>([]) //上传文件列表
//上传文件时，传输的参数
const uploadParams = {
	//user: storeUser.id,
}
// 上传文件时，headers参数
const uploadHeaders = {
	//Authorization: `Bearer ${import.meta.env.VITE_API_KEY}`,
}
const value=ref('') //对话框写的文本内容

const {llmMap} = useKV() //大模型选项列表定义
const llmMode = ref('deepseek-v3')

/* refNode */
const refAttachments=ref()

/* methods */
const uploadTitle = computed(()=>{
	if(uploadType.value===0)	return '拍照或上传图片 (每张10M以内)'
	return '上传文档 (每个10M以内)'
})
const uploadPlaceholder = computed(()=>{
	if(uploadType.value===0){
		return ()=>{return {
			icon: h(PictureOutlined), title: undefined,
			description: '支持png、jpg、jpeg等格式',
		}}
	}
	return ()=>{return {
		icon: h(FileAddOutlined), title: undefined,
		description: '支持pdf、word、excel、txt等格式',
	}}
})

const uploadAccept = computed(()=>{
	if(uploadType.value<1){
		//return 'image/jpeg,image/png,image/gif,image/webp,image/tiff,image/vnd.svf,'
		return 'image/*'
	}else if(uploadType.value===1){
		return 'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,' //doc,docx
			+ 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,' //xls,xlsx
			+ 'application/vnd.ms-works,' //wps
			+ 'application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,' //ppt,pptx
			+ 'application/pdf,' //pdf
			+ 'text/plain,'// txt
			+ 'text/xml,application/xml,'  //xml
			+ '.md,' //md
			+ 'application/zipapplication/x-zip-compressed' //zip
	}else{
		return 'audio/*' //uploadType.value===2时，音频文件
	}
})
const llmActive = computed(()=>{
	return llmMap[llmMode.value as keyof typeof llmMap]
})

/* 语音转文字hooks*/
const {	recording, speechOption,setFinishFunc} = useRecord(props)
setFinishFunc((str:string) => {
	value.value = str
})

/* methods */
//消息发送事件
const handleMsgSubmit = (msg:string)=>{
	inPush.value = true;
	const message = msg.trim()
	if(message==='') return
	emit('onSend',{
		msg:message,
		mode:llmMode.value,
		linkNet:linkNet.value,
		uploadType:uploadType.value,
		uploadList:linkNet.value? []:fileItems.value,
	});
	value.value = ''
	fileItems.value = []
	headerOpen.value = false
}
const handleCancel = ()=>{
	message.warning('stop Send');
	inPush.value = false;
	emit('onCancel');
}
const handleFileListChange = (info:any) => {
	//console.log(info.file)
	fileItems.value = info.fileList
	if(info.fileList.length===0)	headerOpen.value=false
	if(info.file.status==='done'){
		info.file.uid= info.file.response.id
		//info.file.type = info.file.response.mime_type
		if(info.file.response.extension in ['jpeg','jpg','png','gif','webp','tiff','svg']){
			info.file.type = 'image'
		}else if(info.file.response.extension in ['doc','docx','xls','xlsx','wps','ppt','pptx','pdf','txt','xml','zip','md']){
			info.file.type = 'document'
		}
	}

}
const handleChangeUploadType =(type:number)=>{
	uploadType.value = type;
	fileItems.value=[];
	uploadTypeChangeConfirm.value = false
	headerOpen.value = true;
	if(fileItems.value.length===0) {
		nextTick(() => {
			//触发展开后点击附件的方法
			const element = document.querySelector(".ant-attachment-placeholder-inner") as HTMLElement | null;
			element?.click()
		})
	}
}

//切换大模型选项
const handleLlmChangeClick: MenuProps['onClick'] = ({ key }) => {
	//console.log(`Click on item ${key}`);
	llmMode.value = key as string
};

//切换是否联网搜索
const switchNetSearch= ()=>{
	if(!inPush.value) linkNet.value = !linkNet.value;
	//todo: 还要加入业务逻辑！
}
//展开/收起header附件区
const switchHeaderOpen = (type:number) => {
	if(recording.value)	return; //录制音频时，不能上传附件
	if(uploadType.value!==type){
		if(uploadType.value===-1){
			handleChangeUploadType(type)
		}else{
			uploadTypeChangeConfirm.value = true;
		}
	}else{
		if(headerOpen.value === false){
			headerOpen.value=true
			if(fileItems.value.length===0) {
				nextTick(() => {
					//触发展开后点击附件的方法
					const element = document.querySelector(".ant-attachment-placeholder-inner") as HTMLElement | null;
					element?.click()
				})
			}
		}
		else{//收起header上传区
			headerOpen.value = false
			if(fileItems.value.length===0){
				uploadType.value=-1;
			}
		}
	}
}

const getPopupContainer=()=>{
	return document.querySelector('.sender-wrapper') as HTMLElement
}

// 重设置文本框里的内容
const setTextContent = (text:string)=>{
	value.value = text;
}

onMounted(()=>{
	nextTick(()=>{
		const attach = document.querySelector('.ant-attachment')
		if(attach){
			const inputs = attach.querySelectorAll('input');
			for(const input of inputs){
				input.removeAttribute('capture')
			}
		}
	})
})

defineExpose({
	inPush,value,llmMode, linkNet, //data
	setTextContent, handleMsgSubmit, //methods
})
</script>

<template>
	<div class="sender-wrapper" id="sender-wrapper">
		<Sender :loading="inPush" :allow-speech="speechOption" placeholder="电脑端请用 `Shift + Enter` 键换行" v-model:value="value"
				@submit="handleMsgSubmit" @cancel="handleCancel" :styles="{input:{maxHeight:'100px'}}">
			<template v-if="uploadImageEnable||uploadDocumentEnable" #header>
				<Sender.Header :open="headerOpen && !linkNet" :forceRender="true" :title="uploadTitle">
					<Attachments ref="refAttachments" overflow="scrollX" :max-count="maxUploadCount" :headers="uploadHeaders" :accept="uploadAccept"
								 :action="uploadUrl+'/'+props.source" :items="fileItems" :data="uploadParams" :placeholder="uploadPlaceholder"
								 @change ="handleFileListChange" @beforeUpload="() => false" @preview="()=>{}"/>
					<div class="stat-upload"><span class="count">{{fileItems.length}}</span> / {{maxUploadCount}}</div>
				</Sender.Header>
			</template>
			<template #prefix>
				<a-dropdown placement="topLeft" :arrow="true" :trigger="['click']" :disabled="inPush||recording">
				<div class="switch-button switch-button-border">
					<img :src="llmActive?.imgPath" alt=""/> <span>{{llmActive?.label}}</span> <DownOutlined />
				</div>
					<template #overlay>
						<a-menu @click="handleLlmChangeClick">
							<template v-for="(item,index) in llmMap" :key="index">
								<a-menu-item> <img style="width:16px;height:16px;margin-right:4px;" :src="item.imgPath" alt=""/> <span>{{index}}</span> </a-menu-item>
							</template>
						</a-menu>
					</template>
				</a-dropdown>
				<div class="switch-button" :class="linkNet? 'btn-active':null" @click="switchNetSearch">
					<GlobalOutlined/><span>联网</span>
				</div>
				<i class="between"/>
				<a-tooltip  :title="'上传图片 (最多'+maxUploadCount+'张,每张10M以内)'" placement="top" :arrow="false" :getPopupContainer="getPopupContainer">
					<a-button v-if="uploadImageEnable && !linkNet" type="text" :icon="h(PictureOutlined)" @click="switchHeaderOpen(0)" :class="uploadType===0&&headerOpen? 'active':null"/>
				</a-tooltip>
				<a-tooltip :title="['上传文档 (最多'+maxUploadCount+'个,每个10M以内)；\n','支持word、excel、pdf、txt等格式']" placement="top" :arrow="false" :getPopupContainer="getPopupContainer">
					<a-button v-if="uploadDocumentEnable && !linkNet" type="text" :icon="h(PaperClipOutlined)" @click="switchHeaderOpen(1)" :class="uploadType===1&&headerOpen? 'active':null"/>
				</a-tooltip>
			</template>
		</Sender>
	</div>
	<a-modal v-if="uploadImageEnable&&uploadDocumentEnable" v-model:open="uploadTypeChangeConfirm" title="提示" centered @ok="handleChangeUploadType(uploadType===0? 1:0)">
		<p>变更上传文件种类将清除当前已传附件，是否确认变更？</p>
	</a-modal>
</template>

<style scoped lang="scss">
:deep(.ant-sender .ant-sender-content){ flex-wrap:wrap; gap:12px; }
:deep(.ant-sender .ant-sender-input){width:100%; max-height:132px!important; min-height:44px!important; overflow-y:auto!important;}
:deep(.ant-sender .ant-sender-actions-list){
	width:100%;justify-content: flex-end;
	.anticon.anticon-audio{font-size:18px;}
}
:deep(.ant-sender .ant-sender-prefix){
	position:absolute; bottom:12px;right:86px;left:12px; display: flex; gap:4px; align-items:center; justify-content:flex-end;flex-shrink: 0; height:32px;
	.ant-btn-text{
		display:inline-flex; align-items: center; justify-content: center; color:var(--primary-color);
		.anticon{font-size:18px;}
	}
}
:deep(.ant-sender-header-content){padding:0}
:deep(.ant-attachment-list-card-type-preview .ant-attachment-list-card-img-mask){background: transparent;}
:deep(.ant-attachment-list-card .ant-attachment-list-card-remove){
	font-size:20px;opacity: 1;transform: translate(40%, -40%); border-radius: 0 6px 0 50%; padding:2px;
	background-color:var(--attachment-remove-color);
	.anticon{color:var(--font-base-color);}
}
:deep(.ant-attachment .ant-attachment-list){padding-block: 10px; padding-inline: 10px; gap:10px}
:deep(.ant-attachment-list-card .ant-attachment-list-card-remove){display:block;}
:deep(.ant-attachment-placeholder){backdrop-filter:none;}
:deep(.ant-attachment-placeholder-inner){
	gap:0;
	.anticon{
		color:var(--info-color);
		& + .anticon{margin-left:20px;}
	}

}
.active,active:hover{ background:rgba(0,0,0,.2)!important; }
:deep(.ant-btn-text:not(:disabled):hover){ background-color:rgba(0,0,0,.2)!important; }
.sender-wrapper{margin:0 16px; padding-top:10px;}
.between{width:0;margin-right: auto}
.switch-button{
	height:28px;padding:0 8px; display:inline-flex; align-items: center; border-radius: 15px; background-color: var(--bg-link-hover-color);
	color:var(--font-base-color); cursor: pointer;
	&-border{border:1px solid var(--primary-color);}
	>img{width:16px;height:16px;margin-right:4px}
	&.btn-active{
		color:var(--primary-color); overflow: hidden; background-color: color-mix(in srgb, var(--primary-color) 15%, white);
	}
	.anticon{
		font-size:16px;
		&.anticon-down{font-size:10px!important;margin-left:8px}
	}
	&>.anticon+span{margin-inline-start:4px;}
}
html.dark .switch-button{
	&.btn-active{
		color:var(--primary-color); overflow: hidden; background-color: color-mix(in srgb, var(--primary-color) 15%, #111111);
	}
}
.stat-upload{
	position: absolute; right:10px;top:10px;color:var(--font-placeholder-color);
	.count{color: var(--primary-color);}
}
@media (max-width: 767px){
	:deep(.ant-tooltip){display:none!important;}
}
</style>